﻿namespace FSharpChess
//Used in Evaluation
type oHashType =
    |Exact
    |Alpha
    |Beta
//storage of best move
type BestMove =
    {
        bmHashCodeA: uint64;
        bmHashCodeB: uint64;
        bmDepth: int;
        bmType: oHashType;
        bmIsWhite: bool;
        bmResult: int;
        bmMoveName: oMoveName;
        bmFrom: int;
        bmTo: int;
        bmPcCapId: int;
    }
    static member create(hashCodeA,hashCodeB,hdepth,valu,etype,mfrom,mto,moveName,iswhite,pccapid) =
        {
            bmHashCodeA = hashCodeA;
            bmHashCodeB = hashCodeB;
            bmDepth = hdepth;
            bmType = etype;
            bmIsWhite = iswhite;
            bmResult = valu;
            bmMoveName = moveName;
            bmFrom = mfrom;
            bmTo = mto;
            bmPcCapId = pccapid;
        }
    static member blank = BestMove.create(0UL,0UL,-1,-1,Exact,-1,-1,NullMove,true,-1)
    static member ct = 1048576
    static member copy(b) =
        let cbmHashCodeA = b.bmHashCodeA
        let cbmHashCodeB = b.bmHashCodeB
        let cbmDepth = b.bmDepth
        let cbmType = b.bmType
        let cbmIsWhite = b.bmIsWhite
        let cbmResult = b.bmResult
        let cbmMoveName = b.bmMoveName
        let cbmFrom = b.bmFrom
        let cbmTo = b.bmTo
        let cbmPcCapId = b.bmPcCapId
        BestMove.create(cbmHashCodeA,cbmHashCodeB,cbmDepth,cbmResult,cbmType,cbmFrom,cbmTo,cbmMoveName,cbmIsWhite,cbmPcCapId)

module Bms =
    let BestMove_Blank = BestMove.blank
    let Move_Blank = Move.blank
    let arr = Array.create BestMove.ct BestMove_Blank
    let ProbeHash(depth, alpha, beta, iswhite, fiftyMoveDrawBase , psn) =
        let i = (int)(psn.Hca % (uint64)BestMove.ct)
        let cur=arr.[i]
        if cur.bmHashCodeA = psn.Hca && cur.bmHashCodeB = psn.Hcb && cur.bmDepth>=depth && cur.bmIsWhite=iswhite then
            if cur.bmType = Exact then
                (cur.bmResult,psn.CreateMove(cur.bmMoveName, psn.Sqs.[cur.bmFrom], cur.bmFrom, cur.bmTo, cur.bmPcCapId, cur.bmResult))
            elif cur.bmType=Alpha && cur.bmResult<=alpha then
                (alpha,psn.CreateMove(cur.bmMoveName, psn.Sqs.[cur.bmFrom], cur.bmFrom, cur.bmTo, cur.bmPcCapId, cur.bmResult))
            elif cur.bmType=Beta && cur.bmResult>=beta then
                (beta,psn.CreateMove(cur.bmMoveName, psn.Sqs.[cur.bmFrom], cur.bmFrom, cur.bmTo, cur.bmPcCapId, cur.bmResult))
            else
                (System.Int32.MinValue,psn.CreateMove(cur.bmMoveName, psn.Sqs.[cur.bmFrom], cur.bmFrom, cur.bmTo, cur.bmPcCapId, cur.bmResult))
        else
            (System.Int32.MinValue,Move_Blank)        
    let RecordHash(hdepth, valu, etype, mv, colour, psn) =
        let i = (int)(psn.Hca % (uint64)BestMove.ct)
        //could change to allow for multiple entries
        if arr.[i].bmHashCodeA=0UL || arr.[i].bmDepth<hdepth then
            let newBM = BestMove.create(psn.Hca,psn.Hcb,hdepth,valu,etype,mv.From,mv.To,mv.mvName,colour,mv.pieceCaptured)
            arr.[i]<-newBM
    let ProbeForBestMove(iswhite,fiftyMoveDrawBase,psn) =
        let i = (int)(psn.Hca % (uint64)BestMove.ct)
        let cur=arr.[i]
        if cur.bmHashCodeA = psn.Hca && cur.bmHashCodeB = psn.Hcb && iswhite=cur.bmIsWhite then
            psn.CreateMove(cur.bmMoveName, psn.Sqs.[cur.bmFrom], cur.bmFrom, cur.bmTo, cur.bmPcCapId, cur.bmResult)
        else
            Move_Blank
    let reset() = for i = 0 to BestMove.ct-1 do arr.[i] <- BestMove_Blank
